package es7

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/olivere/elastic/v7"
	"ipfs-browser/src/Metadata"
	"ipfs-browser/src/tool"
	"log"
	"os"
	"time"
)

var client *elastic.Client

//initialization
func Init() (err error) {
	errorlog := log.New(os.Stdout, "APP", log.LstdFlags)
	cfg, err := tool.ParseConfig("./config/app.json")
	if err != nil {
		return err
	}
	searchEngine := cfg.SearchEngine
	url := searchEngine.Host + ":" + searchEngine.Port + "/"
	client, err = elastic.NewClient(elastic.SetErrorLog(errorlog), elastic.SetURL(url))
	if err != nil {
		return err
	}
	info, code, err := client.Ping(url).Do(context.Background())
	if err != nil {
		return err
	}
	fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)
	fmt.Println("initialization complete!")
	return nil
}
func DeleteIndex(idx string) {
	exists, err := client.IndexExists(idx).Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	if !exists {
		fmt.Println("index does not exist")
		return
	}
	_, err = client.DeleteIndex(idx).Do(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println("index: ", idx, " has been deleted")
}

//adds a document to an index
func AddDocument(idx string, e Metadata.Metadata) (msg string, err error) {
	m := "上传成功"
	exists, err := client.IndexExists(idx).Do(context.Background())
	if err != nil {
		m = "上传失败"
		return m, err
	}
	if exists && isExist(idx, e.CID) {
		fmt.Println("the file has been exist")
		m = "文件之前已上传"
		return m, nil
	} else {
		re, err := client.Index().
			Index(idx).
			BodyJson(e).
			Do(context.Background())
		log.Println("add to index:", re.Index)
		if err != nil {
			// Handle error
			m = "上传失败"
			return m, err
		}
	}
	fmt.Println(m)
	time.Sleep(time.Second * 2)
	return m, nil
}

//delete a document from an index
func DeleteDocument(idx string, cid string) (err error) {
	s := "cid: " + cid
	q := elastic.NewQueryStringQuery(s)
	res, err := client.Search(idx).Query(q).Do(context.Background())
	for _, hit := range res.Hits.Hits {
		id := hit.Id
		_, err = client.Delete().Index(idx).Id(id).Do(context.Background())
		if err != nil {
			return err
		}
	}
	fmt.Print("Document deleted from from index\n")
	return nil
}
func isExist(idx string, cid string) bool {
	matchPhraseQuery := elastic.NewMatchPhraseQuery("cid", cid)
	res, err := client.Search().Query(matchPhraseQuery).Do(context.Background())
	if err != nil {
		fmt.Println(err.Error())
	}
	if res.Hits.TotalHits.Value > 0 {
		//fmt.Println(res.Hits.TotalHits.Value)
		return true
	} else {
		// No hits
		return false
	}
}

//搜索
func Query(idx string, keyWord string) (results []Metadata.Metadata, e error) {
	var res *elastic.SearchResult
	var err error

	//matchPhraseQuery := elastic.NewMatchPhraseQuery("description", keyWord)
	matchQuery := elastic.NewMatchQuery("description", keyWord).Fuzziness("AUTO")
	if idx == "all" {
		res, err = client.Search().Query(matchQuery).Do(context.Background())

		//res, err = client.Search().Query(matchPhraseQuery).Do(context.Background())
	} else {
		res, err = client.Search(idx).Query(matchQuery).Do(context.Background())
		//res, err = client.Search(idx).Query(matchPhraseQuery).Do(context.Background())
	}
	printResult(res, err)
	if res.Hits.TotalHits.Value > 0 {
		fmt.Println("we have found results of ", res.Hits.TotalHits.Value)
	} else {
		// No hits
		fmt.Print("Found nothing\n")
	}
	return handleResults(res, err)
}

func QueryByCid(cid string) (result Metadata.Metadata, err error) {
	var res *elastic.SearchResult
	matchPhraseQuery := elastic.NewMatchPhraseQuery("cid", cid)
	res, err = client.Search().Query(matchPhraseQuery).Do(context.Background())
	json.Unmarshal(res.Hits.Hits[0].Source, &result)
	fmt.Println(result)
	return
}

// print the result of query
func printResult(res *elastic.SearchResult, err error) {

	if err != nil {
		fmt.Println(err.Error())
		return
	}
	var result Metadata.Metadata
	for _, item := range res.Hits.Hits { //从搜索结果中取数据的方法
		err = json.Unmarshal(item.Source, &result)
		if err != nil {
			fmt.Println("[Unmarshall Error] ", err)
		}
		fmt.Println(result)
	}
}

// handle the result of query
func handleResults(res *elastic.SearchResult, err error) (results []Metadata.Metadata, e error) {
	if err != nil {
		return nil, err
	}
	//var results []Metadata.Metadata
	for _, item := range res.Hits.Hits {
		var result Metadata.Metadata
		err = json.Unmarshal(item.Source, &result)
		if err != err {
			return nil, err
		}
		results = append(results, result)
	}
	//fmt.Println(results)
	return results, nil

}
func Test() {
	idx := "test"
	fmt.Println(1)
	Init()
	//DeleteIndex(idx)
	//time.Sleep(time.Second * 10)
	//CreateIndex(idx)
	fmt.Println(2)
	e1 := Metadata.Metadata{"first", "i am the first and best", "cidsghdkahbjmghjkk", "test", time.Now()}
	e2 := Metadata.Metadata{"second", "i am the second but also good", "cidshkkh34h8k", "test", time.Now()}

	AddDocument(idx, e2)
	AddDocument(idx, e1)

	//m, _ := QueryByCid("QmUac6x86vLuaejCqkFbPLpUT6KYuqfwWoFn4KTicffEjj")
	//fmt.Println("m:", m)
	//fmt.Println("i have waited for 20 seconds")
	fmt.Println(3)
	Query(idx, "best")
	Query(idx, "good")
	DeleteIndex("test")
	DeleteIndex("picture")
	/*fmt.Println(4)
	DeleteDocument(idx, "cidsghdkahbjmghjkk")
	DeleteDocument(idx, "cidshkkh34h8k")
	time.Sleep(time.Second * 10)
	//fmt.Println("i have waited for 5 seconds")
	fmt.Println(5)
	Query(idx, "best")
	Query(idx, "good")*/
}
